﻿#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <vector>
#include <queue>
#include <unordered_map>
using namespace std;
// 原题连接：https://leetcode.cn/problems/course-schedule/description/
/*
题目描述：
你这个学期必须选修 numCourses 门课程，记为 0 到 numCourses - 1 。

在选修某些课程之前需要一些先修课程。 先修课程按数组 prerequisites 给出，其中 prerequisites[i] = [ai, bi] ，表示如果要学习课程 ai 则 必须 先学习课程  bi 。

例如，先修课程对 [0, 1] 表示：想要学习课程 0 ，你需要先完成课程 1 。
请你判断是否可能完成所有课程的学习？如果可以，返回 true ；否则，返回 false 。



示例 1：

输入：numCourses = 2, prerequisites = [[1,0]]
输出：true
解释：总共有 2 门课程。学习课程 1 之前，你需要完成课程 0 。这是可能的。
示例 2：

输入：numCourses = 2, prerequisites = [[1,0],[0,1]]
输出：false
解释：总共有 2 门课程。学习课程 1 之前，你需要先完成​课程 0 ；并且学习课程 0 之前，你还应先完成课程 1 。这是不可能的。


提示：

1 <= numCourses <= 2000
0 <= prerequisites.length <= 5000
prerequisites[i].length == 2
0 <= ai, bi < numCourses
prerequisites[i] 中的所有课程对 互不相同
*/


// 开始解题：
// 方法——拓扑排序
class Solution {
public:
    bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {
        // 先建图
        unordered_map<int, vector<int>> edges(numCourses);
        vector<int> in(numCourses);
        for (auto e : prerequisites) {
            int a = e[0], b = e[1];
            edges[b].push_back(a);
            in[a]++;
        }
        // 将入度为0的节点全都放入到队列中
        queue<int> q;
        for (int i = 0; i < numCourses; i++) {
            if (0 == in[i]) {
                q.push(i);
            }
        }
        while (!q.empty()) {
            int t = q.front();
            q.pop();
            for (auto it : edges[t]) {
                in[it]--;
                if (0 == in[it]) {
                    q.push(it);
                }
            }
        }
        for (auto it : in) {
            if (it) {
                return false;
            }
        }
        return true;

    }
};